package gbench.sandbox.matrix.img.util;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jblas.DoubleMatrix;

import gbench.common.fs.XlsFile.DataMatrix;

/**
 * JBlas 的 Matrix 的工具类
 * @author gbench
 *
 */
public class BlasMatrix {
    
    
    /**
     * 
     * @param dblmx
     * @return
     */
    public static double[][] unbox(final Double[][] dblmx) {
        final var m = dblmx.length;
        final var mm = new double[m][];
        for (int i = 0; i < m; i++) mm[i] = unbox(dblmx[i]);
        return mm;
    }
    
    /**
     * null 会被视为0
     * @param dd
     * @return
     */
    public static double[] unbox (final Double[] dd) {
        final var n = dd.length;
        final var nn = new double[n];
        for (int j = 0; j < n; j++)
            nn[j] = dd[j]==null?0d:dd[j];
        return nn;
    }
    
    /**
     * 
     * @param dblmx
     * @return
     */
    public static Double[][] box(final double[][] dblmx) {
        final var m = dblmx.length;
        final var mm = new Double[m][];
        for (int i = 0; i < m; i++) mm[i] = box(dblmx[i]);
        return mm;
    }
    
    /**
     * 
     * @param dd
     * @return
     */
    public static Double[] box (final double[] dd) {
        final var n = dd.length;
        final var nn = new Double[n];
        for (int j = 0; j < n; j++)
            nn[j] = dd[j];
        return nn;
    }

    /**
     * DoubleMatrix 转  DataMatrix 
     * 
     * @param dd
     * @return
     */
    public static DataMatrix<Double> dmx (final DoubleMatrix cells) {
        return DataMatrix.of(box(cells.toArray2()),true);
    }
    
    /**
     * Object[] 转  DataMatrix 
     * 
     * @param dd
     * @return
     */
    public static DataMatrix<Double> dmx (final Object[] cells) {
        if(cells instanceof Double[][]) {
            return DataMatrix.of((Double[][])cells,true);
        }else if(cells instanceof Double[]) {
            final Double[][] cc = new Double[][] {(Double[])cells};
            return DataMatrix.of(DataMatrix.transpose(cc),true);
        }else {
            return null;
        }
    }

    /**
     * 
     * @param dd
     * @return
     */
    public static DoubleMatrix of (final Double[][] dd) {
        return new DoubleMatrix(unbox(dd));
    }
    
    /**
     * 
     * @param dd
     * @return
     */
    public static DoubleMatrix of (final double[][] dd) {
        return new DoubleMatrix(dd);
    }
    
    /**
     * 
     * @param dd
     * @return
     */
    public static DoubleMatrix of (final double[] dd) {
        return new DoubleMatrix(dd);
    }
    
    /**
     * 
     * @param dd
     * @return
     */
    public static DoubleMatrix of (final Double[] dd) {
        return new DoubleMatrix(unbox(dd));
    }
    
    /**
     * 
     * @param dd Double[] 或是 Double[][] 类型的数组
     * 该函的的出现主要是为了解决 诸如：NVec.of(1d).reshape(BlasMatrix::of, 10,3) 直接构造 DoubleMatrix 的问题。
     * @return
     */
    public static DoubleMatrix of (final Object[] dd) {
        if(dd==null)return null;
        if(dd instanceof Double[][]) {
            return new DoubleMatrix(unbox((Double[][])dd));
        }else if(dd instanceof Double[]) {
            return new DoubleMatrix(unbox((Double[])dd));
        }else {
            return null;
        }
    }
    
    /**
     * DataMatrix 转  DoubleMatrix 
     * 
     * @param dmx DoubleMatrix
     * @return DoubleMatrix
     */
    public static DoubleMatrix of (final DataMatrix<Double> dmx) {
        return dmx.getCells(BlasMatrix::of);
    }
    
    /**
     * 
     * @param matrix
     * @return
     */
    public static Stream<double[]> stream(final DoubleMatrix matrix){
        return stream(matrix,e->e);
    }
    
    /**
     * 行流
     * @param matrix
     * @return
     */
    public static Stream<Double[]> dblS(final DoubleMatrix matrix){
        return stream(matrix,BlasMatrix::box);
    }
    
    /**
     * 核心函数
     * @param <T> mapper 的 值类型
     * @param matrix
     * @param mapper 行变换函数 
     * @return
     */
    public static <T> Stream<T> stream(final DoubleMatrix matrix, final Function<double[],T> mapper){
        return Arrays.stream(matrix.toArray2()).map(mapper);
    }
    
    /**
     * 列流
     * @param matrix
     * @return
     */
    public static Stream<double[]> stream2(final DoubleMatrix matrix){
        return stream2(matrix,e->e);
    }
    
    /**
     * 列流
     * @param matrix
     * @return
     */
    public static Stream<Double[]> dblS2(final DoubleMatrix matrix){
        return stream2(matrix,BlasMatrix::box);
    }
    
    /**
     * 列流  <br>
     * 核心函数
     * @param <T> mapper 的 值类型
     * @param matrix
     * @param mapper 列变换函数 
     * @return
     */
    public static <T> Stream<T> stream2(final DoubleMatrix matrix, final Function<double[],T> mapper){
        return Arrays.stream(matrix.transpose().toArray2()).map(mapper);
    }
    
    /**
     * 行列表  <br>
     * @param <T> mapper 的 值类型
     * @param matrix
     * @param mapper 行变换函数 
     * @return
     */
    public static <T> List<T> list(final DoubleMatrix matrix, final Function<double[],T> mapper){
        return BlasMatrix.stream(matrix,mapper).collect(Collectors.toList());
    }
    
    /**
     * 列列表  <br>
     * @param <T> mapper 的 值类型
     * @param matrix
     * @param mapper 列变换函数 
     * @return
     */
    public static <T> List<T> list2(final DoubleMatrix matrix, final Function<double[],T> mapper){
        return BlasMatrix.stream2(matrix,mapper).collect(Collectors.toList());
    }
}
